#include <iostream>
#include <algorithm>
#include <functional>
#include <string>
#include <vector>
#include <unordered_map>
#include <mutex>
#include <condition_variable>
#include <thread>
#include <memory>
#include <utility>
#include <assert.h>
#include <string.h>
#include <time.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/epoll.h>
#include <sys/eventfd.h>
#include <sys/timerfd.h>
#include <signal.h>

using TaskFunc = std::function<void()>;
using ReleaseFunc = std::function<void()>;

class Timer
{
private:
    uint64_t _tid;     // 定时任务对象的id
    int _timeout;      // 定时任务的超时时间
    TaskFunc _task_cb; // 定时任务的包装器对象，实际调用时会回调用户自己设置的定时任务
    ReleaseFunc _release;// 定时器对象销毁时，除了执行定时任务外，也会顺便释放TimerWheel中哈希表保存的Timer对象信息
    bool _canceled; // 该定时任务是否被取消
public:
    Timer(uint64_t tid, int timeout, TaskFunc task_cb)
        : _tid(tid), _timeout(timeout), _task_cb(task_cb), _canceled(false) {}
    ~Timer()
    {
        if (_canceled == false) _task_cb(); // 执行定时任务
        _release(); // 用于释放时间轮中保存的weakptr定时器对象信息
    }
    void SetDestruct(ReleaseFunc cb) { _release = cb; }
    int TimeOut() { return _timeout; }
    void Cancel() { _canceled = true; }
};
class TimerWheel
{
private:
    int _tick;     // 秒针
    int _capacity; // 表盘的最大刻度---最大延迟时间
    std::unordered_map<uint64_t, std::weak_ptr<Timer>> _timers;
    //时间轮内需要管理多个Timer对象，哈希表可以帮助我们通过定时任务对象的id来查找Timer对象本身
    std::vector<std::vector<std::shared_ptr<Timer>>> _wheel;
    //保存shared_ptr管理的多个Timer对象，实现秒级时间轮
private:
    void ReleaseWeakptr(uint64_t tid)
    {
        auto it = _timers.find(tid);
        if (it != _timers.end()) _timers.erase(tid);
    }
public:
    TimerWheel() : _capacity(60), _tick(0), _wheel(_capacity) {}
    void AddTimer(uint64_t tid, int timeout, TaskFunc task_cb)
    {
        std::shared_ptr<Timer> sp(new Timer(tid, timeout, task_cb));
        sp->SetDestruct(std::bind(&TimerWheel::ReleaseWeakptr, this, tid));
        _wheel[timeout].push_back(sp);
        _timers[tid] = std::weak_ptr<Timer>(sp);    
    }
    void FlushTimer(uint64_t tid)
    {
        // 1.通过保存的weak_ptr定时器对象，构造一个shared_ptr出来，将shared_ptr插入到wheel时间轮当中
        auto it = _timers.find(tid);
        if (it == _timers.end()) return;
        std::shared_ptr<Timer> sp = it->second.lock();
        // 2.获取定时任务的延迟时间
        int timeout = sp->TimeOut();
        // 3.确定添加sp的位置
        int pos = (_tick + timeout) % 60; // tick走的下标的范围是[0, 59]
        _wheel[pos].push_back(sp);        // 刷新定时任务
    }
    void CancelTimer(uint64_t tid)
    {
        // 1.通过保存的weak_ptr定时器对象，构造一个shared_ptr出来，通过shared_ptr拿到定时器对象的详细信息
        auto it = _timers.find(tid);
        if (it == _timers.end()) return;
        std::shared_ptr<Timer> sp = it->second.lock();
        // 2.取消定时任务
        sp->Cancel();
    }
    void RunTimer() // 这个函数应该每秒钟执行一次
    {
        _tick = (_tick + 1) % _capacity;
        _wheel[_tick].clear(); // 清空指定位置的数组，则销毁该vector中的所有shared_ptr对象
    }
};
